package com.mygame.gateway.server;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.BiConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import io.netty.channel.Channel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;

@Service
public class ChannelService {
	private Map<Long, Channel> playerChannelMap = new HashMap<>();// playerId与Netty
																	// Channel的映射容器，这里使用的是HashMap，所以，对于Map的操作都要放在锁里面
	private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁,使用非公平锁
	private Logger logger = LoggerFactory.getLogger(ChannelService.class);

	private void readLock(Runnable task) {// 封装添加读锁，统一添加，防止写错
		lock.readLock().lock();
		try {
			task.run();
		} catch (Exception e) { // 统一异常捕获
			logger.error("ChannelService读锁处理异常", e);
		} finally {
			lock.readLock().unlock();
		}
	}

	private void writeLock(Runnable task) {// 封装添加写锁，统一添加，防止写错
		lock.writeLock().lock();
		try {
			task.run();
		} catch (Exception e) { // 统一异常捕获
			logger.error("ChannelService写锁处理异常", e);
		} finally {
			lock.writeLock().unlock();
		}
	}

	public void addChannel(Long playerId, Channel channel) {
		this.writeLock(() -> {// 数据写入，添加写锁
			playerChannelMap.put(playerId, channel);
			channel.closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {

				@Override
				public void operationComplete(Future<? super Void> future) throws Exception {
					logger.debug("player {} 连接 {} 断开", playerId, channel.id().asShortText());
					removeChannel(playerId, channel);
				}
			});
		});
	}

	public Channel getChannel(Long playerId) {
		lock.readLock().lock();
		try {
			Channel channel = this.playerChannelMap.get(playerId);
			return channel;
		} finally {
			lock.readLock().unlock();
		}
	}

	public void removeChannel(Long playerId, Channel removedChannel) {
		this.writeLock(() -> {
			Channel existChannel = playerChannelMap.get(playerId);
			if (existChannel != null && existChannel == removedChannel) {// 必须是同一个对象才可以移除
				playerChannelMap.remove(playerId);
				existChannel.close();
			}
		});
	}

	public void broadcast(BiConsumer<Long, Channel> consumer) {// 向Channel广播消息
		this.readLock(() -> {
			this.playerChannelMap.forEach(consumer);
		});
	}

	public int getChannelCount() {
		lock.writeLock().lock();
		try {
			int size = this.playerChannelMap.size();// 获取连锁的数量
			return size;
		} finally {
			lock.writeLock().unlock();
		}
	}

}
